﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Issues.IssueBase
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using Helpers;
using System;
using System.Collections.Generic;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.ComponentInterfaces;
using TaleWorlds.CampaignSystem.Conversation;
using TaleWorlds.CampaignSystem.GameMenus;
using TaleWorlds.CampaignSystem.GameState;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.CampaignSystem.Settlements.Locations;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.ObjectSystem;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.Issues
{
  public abstract class IssueBase : MBObjectBase
  {
    public const int IssueRelatedConversationPriority = 125;
    [SaveableField(27)]
    private float _totalTroopXpAmount;
    [SaveableField(30)]
    public readonly TroopRoster AlternativeSolutionSentTroops;
    [SaveableField(35)]
    private SkillObject _companionRewardSkill;
    [SaveableField(14)]
    private readonly MBList<JournalLog> _journalEntries;
    [SaveableField(11)]
    private IssueBase.IssueState _issueState;
    [SaveableField(12)]
    public CampaignTime IssueDueTime;
    [SaveableField(16)]
    public CampaignTime IssueCreationTime;
    [SaveableField(13)]
    private Hero _issueOwner;
    [SaveableField(26)]
    private float _issueDifficultyMultiplier;
    [SaveableField(32)]
    private bool _areIssueEffectsResolved;
    [SaveableField(33)]
    private int _alternativeSolutionCasualtyCount;
    [SaveableField(34)]
    private float _failureChance;
    [SaveableField(31)]
    private readonly List<ITrackableCampaignObject> _trackedObjects = new List<ITrackableCampaignObject>();

    protected override void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      base.AutoGeneratedInstanceCollectObjects(collectedObjects);
      collectedObjects.Add((object) this.AlternativeSolutionSentTroops);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.IssueDueTime, collectedObjects);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.IssueCreationTime, collectedObjects);
      collectedObjects.Add((object) this._companionRewardSkill);
      collectedObjects.Add((object) this._journalEntries);
      collectedObjects.Add((object) this._issueOwner);
      collectedObjects.Add((object) this._trackedObjects);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.AlternativeSolutionReturnTimeForTroops, collectedObjects);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.AlternativeSolutionIssueEffectClearTime, collectedObjects);
      collectedObjects.Add((object) this.IssueQuest);
    }

    internal static object AutoGeneratedGetMemberValueAlternativeSolutionReturnTimeForTroops(
      object o)
    {
      return (object) ((IssueBase) o).AlternativeSolutionReturnTimeForTroops;
    }

    internal static object AutoGeneratedGetMemberValueAlternativeSolutionIssueEffectClearTime(
      object o)
    {
      return (object) ((IssueBase) o).AlternativeSolutionIssueEffectClearTime;
    }

    internal static object AutoGeneratedGetMemberValueIssueQuest(object o)
    {
      return (object) ((IssueBase) o).IssueQuest;
    }

    internal static object AutoGeneratedGetMemberValueIsTriedToSolveBefore(object o)
    {
      return (object) ((IssueBase) o).IsTriedToSolveBefore;
    }

    internal static object AutoGeneratedGetMemberValueAlternativeSolutionSentTroops(object o)
    {
      return (object) ((IssueBase) o).AlternativeSolutionSentTroops;
    }

    internal static object AutoGeneratedGetMemberValueIssueDueTime(object o)
    {
      return (object) ((IssueBase) o).IssueDueTime;
    }

    internal static object AutoGeneratedGetMemberValueIssueCreationTime(object o)
    {
      return (object) ((IssueBase) o).IssueCreationTime;
    }

    internal static object AutoGeneratedGetMemberValue_totalTroopXpAmount(object o)
    {
      return (object) ((IssueBase) o)._totalTroopXpAmount;
    }

    internal static object AutoGeneratedGetMemberValue_companionRewardSkill(object o)
    {
      return (object) ((IssueBase) o)._companionRewardSkill;
    }

    internal static object AutoGeneratedGetMemberValue_journalEntries(object o)
    {
      return (object) ((IssueBase) o)._journalEntries;
    }

    internal static object AutoGeneratedGetMemberValue_issueState(object o)
    {
      return (object) ((IssueBase) o)._issueState;
    }

    internal static object AutoGeneratedGetMemberValue_issueOwner(object o)
    {
      return (object) ((IssueBase) o)._issueOwner;
    }

    internal static object AutoGeneratedGetMemberValue_issueDifficultyMultiplier(object o)
    {
      return (object) ((IssueBase) o)._issueDifficultyMultiplier;
    }

    internal static object AutoGeneratedGetMemberValue_areIssueEffectsResolved(object o)
    {
      return (object) ((IssueBase) o)._areIssueEffectsResolved;
    }

    internal static object AutoGeneratedGetMemberValue_alternativeSolutionCasualtyCount(object o)
    {
      return (object) ((IssueBase) o)._alternativeSolutionCasualtyCount;
    }

    internal static object AutoGeneratedGetMemberValue_failureChance(object o)
    {
      return (object) ((IssueBase) o)._failureChance;
    }

    internal static object AutoGeneratedGetMemberValue_trackedObjects(object o)
    {
      return (object) ((IssueBase) o)._trackedObjects;
    }

    protected virtual bool IssueQuestCanBeDuplicated => false;

    public virtual int RelationshipChangeWithIssueOwner { get; protected set; }

    public abstract TextObject IssueBriefByIssueGiver { get; }

    public abstract TextObject IssueAcceptByPlayer { get; }

    public virtual TextObject IssuePlayerResponseAfterLordExplanation
    {
      get => new TextObject("{=sMCN7eCp}Is there any other way to solve this problem?");
    }

    public virtual TextObject IssuePlayerResponseAfterAlternativeExplanation
    {
      get => new TextObject("{=yrPEqZEa}Any other way?");
    }

    public abstract TextObject IssueQuestSolutionExplanationByIssueGiver { get; }

    public virtual TextObject IssueAlternativeSolutionExplanationByIssueGiver => TextObject.Empty;

    public virtual TextObject IssueLordSolutionExplanationByIssueGiver => TextObject.Empty;

    public abstract TextObject IssueQuestSolutionAcceptByPlayer { get; }

    public virtual TextObject IssueAlternativeSolutionAcceptByPlayer => TextObject.Empty;

    public virtual TextObject IssueAlternativeSolutionResponseByIssueGiver => TextObject.Empty;

    public virtual TextObject IssueLordSolutionAcceptByPlayer => TextObject.Empty;

    public virtual TextObject IssueLordSolutionResponseByIssueGiver => TextObject.Empty;

    public virtual TextObject IssueLordSolutionCounterOfferBriefByOtherNpc => TextObject.Empty;

    public virtual TextObject IssueLordSolutionCounterOfferExplanationByOtherNpc
    {
      get => TextObject.Empty;
    }

    public virtual TextObject IssueLordSolutionCounterOfferAcceptByPlayer => TextObject.Empty;

    public virtual TextObject IssueLordSolutionCounterOfferDeclineByPlayer => TextObject.Empty;

    public virtual TextObject IssueLordSolutionCounterOfferAcceptResponseByOtherNpc
    {
      get => TextObject.Empty;
    }

    public virtual TextObject IssueLordSolutionCounterOfferDeclineResponseByOtherNpc
    {
      get => TextObject.Empty;
    }

    public virtual TextObject IssueAsRumorInSettlement => TextObject.Empty;

    public virtual int AlternativeSolutionBaseNeededMenCount { get; }

    public int GetTotalAlternativeSolutionNeededMenCount()
    {
      return this.AlternativeSolutionHasScaledRequiredTroops && this.AlternativeSolutionHero != null ? Campaign.Current.Models.IssueModel.GetTroopsRequiredForHero(this.AlternativeSolutionHero, this) : this.AlternativeSolutionBaseNeededMenCount;
    }

    protected virtual int AlternativeSolutionBaseDurationInDaysInternal { get; }

    public int GetTotalAlternativeSolutionDurationInDays()
    {
      return this.AlternativeSolutionHasScaledDuration && this.AlternativeSolutionHero != null ? (int) Campaign.Current.Models.IssueModel.GetDurationOfResolutionForHero(this.AlternativeSolutionHero, this).ToDays : this.AlternativeSolutionBaseDurationInDaysInternal;
    }

    public int GetBaseAlternativeSolutionDurationInDays()
    {
      return this.AlternativeSolutionBaseDurationInDaysInternal;
    }

    [SaveableProperty(25)]
    public CampaignTime AlternativeSolutionReturnTimeForTroops { get; private set; }

    public abstract bool IsThereAlternativeSolution { get; }

    protected virtual TextObject AlternativeSolutionStartLog { get; }

    protected virtual TextObject AlternativeSolutionEndLogDefault
    {
      get => new TextObject("{=xbvQzR2B}Your men should be on their way.");
    }

    public bool IsThereDiscussDialogFlow => this.IssueDiscussAlternativeSolution != null;

    protected virtual int CompanionSkillRewardXP { get; }

    [SaveableProperty(31)]
    public CampaignTime AlternativeSolutionIssueEffectClearTime { get; private set; }

    public Hero AlternativeSolutionHero
    {
      get
      {
        foreach (TroopRosterElement troopRosterElement in (List<TroopRosterElement>) this.AlternativeSolutionSentTroops.GetTroopRoster())
        {
          if (troopRosterElement.Character.IsHero)
            return troopRosterElement.Character.HeroObject;
        }
        return (Hero) null;
      }
    }

    public virtual bool AlternativeSolutionCondition(out TextObject explanation)
    {
      explanation = (TextObject) null;
      return true;
    }

    public virtual void AlternativeSolutionStartConsequence()
    {
    }

    public virtual bool DoTroopsSatisfyAlternativeSolution(
      TroopRoster troopRoster,
      out TextObject explanation)
    {
      explanation = TextObject.Empty;
      return this.IsThereAlternativeSolution && this.AlternativeSolutionBaseNeededMenCount == 1;
    }

    protected virtual void AlternativeSolutionEndWithFailureConsequence()
    {
    }

    protected virtual void AlternativeSolutionEndWithSuccessConsequence()
    {
    }

    public virtual TextObject IssueDiscussAlternativeSolution { get; }

    public virtual TextObject IssueAlternativeSolutionSuccessLog { get; }

    public virtual TextObject IssueAlternativeSolutionFailLog { get; }

    public virtual bool IsTroopTypeNeededByAlternativeSolution(CharacterObject character) => true;

    public abstract bool IsThereLordSolution { get; }

    protected virtual TextObject LordSolutionStartLog => TextObject.Empty;

    protected virtual TextObject LordSolutionCounterOfferAcceptLog => TextObject.Empty;

    protected virtual TextObject LordSolutionCounterOfferRefuseLog => TextObject.Empty;

    public virtual int NeededInfluenceForLordSolution { get; }

    public virtual Hero CounterOfferHero { get; protected set; }

    public virtual bool LordSolutionCondition(out TextObject explanation)
    {
      explanation = (TextObject) null;
      return true;
    }

    protected virtual void LordSolutionConsequence()
    {
    }

    protected virtual void LordSolutionConsequenceWithRefuseCounterOffer()
    {
    }

    protected virtual void LordSolutionConsequenceWithAcceptCounterOffer()
    {
    }

    public MBReadOnlyList<JournalLog> JournalEntries
    {
      get => (MBReadOnlyList<JournalLog>) this._journalEntries;
    }

    public Hero IssueOwner
    {
      get => this._issueOwner;
      set
      {
        Hero issueOwner = this._issueOwner;
        this._issueOwner = value;
        if (!this.IsSolvingWithAlternative)
          return;
        TextObject textObject = new TextObject("{=gmaqJZyv}You have received a message from {NEW_OWNER.LINK}:{newline}\"Sadly, {OLD_OWNER.LINK} has died. You may continue on your task, however, and report back to me.");
        StringHelpers.SetCharacterProperties("OLD_OWNER", issueOwner.CharacterObject, textObject);
        StringHelpers.SetCharacterProperties("NEW_OWNER", this._issueOwner.CharacterObject, textObject);
        this.AddLog(new JournalLog(CampaignTime.Now, textObject));
      }
    }

    public abstract TextObject Title { get; }

    [SaveableProperty(15)]
    public QuestBase IssueQuest { get; private set; }

    public Settlement IssueSettlement
    {
      get => !this._issueOwner.IsNotable ? (Settlement) null : this.IssueOwner.CurrentSettlement;
    }

    public abstract TextObject Description { get; }

    [SaveableProperty(22)]
    public bool IsTriedToSolveBefore { get; private set; }

    public bool IsOngoingWithoutQuest => this._issueState == IssueBase.IssueState.Ongoing;

    public bool IsSolvingWithQuest
    {
      get => this._issueState == IssueBase.IssueState.SolvingWithQuestSolution;
    }

    public bool IsSolvingWithAlternative
    {
      get => this._issueState == IssueBase.IssueState.SolvingWithAlternativeSolution;
    }

    public bool IsSolvingWithLordSolution
    {
      get => this._issueState == IssueBase.IssueState.SolvingWithLordSolution;
    }

    protected float IssueDifficultyMultiplier
    {
      get
      {
        return (double) this._issueDifficultyMultiplier != 0.0 ? this._issueDifficultyMultiplier : Campaign.Current.Models.IssueModel.GetIssueDifficultyMultiplier();
      }
    }

    protected virtual int RewardGold { get; }

    public float GetActiveIssueEffectAmount(IssueEffect issueEffect)
    {
      return !this._areIssueEffectsResolved ? this.GetIssueEffectAmountInternal(issueEffect) : 0.0f;
    }

    public virtual (SkillObject, int) GetAlternativeSolutionSkill(Hero hero)
    {
      return ((SkillObject) null, 0);
    }

    public virtual IssueBase.AlternativeSolutionScaleFlag AlternativeSolutionScaleFlags
    {
      get => IssueBase.AlternativeSolutionScaleFlag.None;
    }

    public bool AlternativeSolutionHasCasualties
    {
      get
      {
        return this.AlternativeSolutionScaleFlags.HasAnyFlag<IssueBase.AlternativeSolutionScaleFlag>(IssueBase.AlternativeSolutionScaleFlag.Casualties);
      }
    }

    public bool AlternativeSolutionHasScaledRequiredTroops
    {
      get
      {
        return this.AlternativeSolutionScaleFlags.HasAnyFlag<IssueBase.AlternativeSolutionScaleFlag>(IssueBase.AlternativeSolutionScaleFlag.RequiredTroops);
      }
    }

    public bool AlternativeSolutionHasScaledDuration
    {
      get
      {
        return this.AlternativeSolutionScaleFlags.HasAnyFlag<IssueBase.AlternativeSolutionScaleFlag>(IssueBase.AlternativeSolutionScaleFlag.Duration);
      }
    }

    public bool AlternativeSolutionHasFailureRisk
    {
      get
      {
        return this.AlternativeSolutionScaleFlags.HasAnyFlag<IssueBase.AlternativeSolutionScaleFlag>(IssueBase.AlternativeSolutionScaleFlag.FailureRisk);
      }
    }

    protected virtual float GetIssueEffectAmountInternal(IssueEffect issueEffect) => 0.0f;

    protected IssueBase(Hero issueOwner, CampaignTime issueDueTime)
    {
      this._issueOwner = issueOwner;
      this.IssueDueTime = issueDueTime;
      this.IssueDiscussAlternativeSolution = (TextObject) null;
      this.IssueCreationTime = CampaignTime.Now;
      this._issueState = IssueBase.IssueState.Ongoing;
      this.IsTriedToSolveBefore = false;
      this.AlternativeSolutionSentTroops = TroopRoster.CreateDummyTroopRoster();
      this._journalEntries = new MBList<JournalLog>();
      CampaignEvents.OnSettlementOwnerChangedEvent.AddNonSerializedListener((object) this, new Action<Settlement, bool, Hero, Hero, Hero, ChangeOwnerOfSettlementAction.ChangeOwnerOfSettlementDetail>(this.OnSettlementOwnerChanged));
    }

    public override string ToString() => this.StringId;

    public void InitializeIssueBaseOnLoad() => this.OnGameLoad();

    internal void HourlyTickWithIssueManager() => this.HourlyTick();

    protected abstract void OnGameLoad();

    protected abstract void HourlyTick();

    protected abstract QuestBase GenerateIssueQuest(string questId);

    public abstract IssueBase.IssueFrequency GetFrequency();

    protected abstract bool CanPlayerTakeQuestConditions(
      Hero issueGiver,
      out IssueBase.PreconditionFlags flag,
      out Hero relationHero,
      out SkillObject skill);

    public abstract bool IssueStayAliveConditions();

    protected abstract void CompleteIssueWithTimedOutConsequences();

    protected virtual void AfterIssueCreation()
    {
    }

    public virtual bool CanBeCompletedByAI() => true;

    protected virtual void OnIssueFinalized()
    {
    }

    public virtual void OnHeroCanHaveQuestOrIssueInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanLeadPartyInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanHavePartyRoleOrBeGovernorInfoIsRequested(
      Hero hero,
      ref bool result)
    {
    }

    public virtual void OnHeroCanDieInfoIsRequested(
      Hero hero,
      KillCharacterAction.KillCharacterActionDetail causeOfDeath,
      ref bool result)
    {
    }

    public virtual void OnHeroCanBecomePrisonerInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanBeSelectedInInventoryInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanMoveToSettlementInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public virtual void OnHeroCanMarryInfoIsRequested(Hero hero, ref bool result)
    {
    }

    public bool StartIssueWithQuest()
    {
      this._issueDifficultyMultiplier = Campaign.Current.Models.IssueModel.GetIssueDifficultyMultiplier();
      this._issueState = IssueBase.IssueState.SolvingWithQuestSolution;
      this.IssueQuest = this.GenerateIssueQuest(this.StringId + "_quest");
      this.IsTriedToSolveBefore = true;
      this.IssueDueTime = CampaignTime.Never;
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.PlayerStartedIssueQuestClassicSolution, Hero.MainHero);
      return true;
    }

    public void StartIssueWithAlternativeSolution()
    {
      this._issueDifficultyMultiplier = Campaign.Current.Models.IssueModel.GetIssueDifficultyMultiplier();
      IssueModel issueModel = Campaign.Current.Models.IssueModel;
      this._failureChance = this.AlternativeSolutionHasFailureRisk ? issueModel.GetFailureRiskForHero(this.AlternativeSolutionHero, this) : 0.0f;
      if (this.AlternativeSolutionHasCasualties)
      {
        (int, int) causalityForHero = issueModel.GetCausalityForHero(this.AlternativeSolutionHero, this);
        this._alternativeSolutionCasualtyCount = MBRandom.RandomInt(causalityForHero.Item1, causalityForHero.Item2 + 1);
      }
      else
        this._alternativeSolutionCasualtyCount = 0;
      this._companionRewardSkill = issueModel.GetIssueAlternativeSolutionSkill(this.AlternativeSolutionHero, this).Item1;
      this._issueState = IssueBase.IssueState.SolvingWithAlternativeSolution;
      this.IsTriedToSolveBefore = true;
      this._totalTroopXpAmount = (float) (1000.0 + 500.0 * (double) this.IssueDifficultyMultiplier);
      this.AlternativeSolutionReturnTimeForTroops = CampaignTime.DaysFromNow((float) this.GetTotalAlternativeSolutionDurationInDays());
      this.IssueDueTime = this.AlternativeSolutionReturnTimeForTroops;
      this.AddLog(new JournalLog(CampaignTime.Now, this.AlternativeSolutionStartLog, new TextObject("{=VFO7rMzK}Return Days"), range: this.AlternativeSolutionBaseDurationInDaysInternal));
      this.AlternativeSolutionIssueEffectClearTime = this.AlternativeSolutionReturnTimeForTroops - CampaignTime.Days(1f);
      if (this.AlternativeSolutionIssueEffectClearTime.IsPast)
        this.AlternativeSolutionIssueEffectClearTime = this.AlternativeSolutionReturnTimeForTroops;
      DisableHeroAction.Apply(this.AlternativeSolutionHero);
      if (LocationComplex.Current != null)
      {
        Location locationOfCharacter = LocationComplex.Current.GetLocationOfCharacter(this.AlternativeSolutionHero);
        if (locationOfCharacter != null)
          LocationComplex.Current.ChangeLocation(locationOfCharacter.GetLocationCharacter(this.AlternativeSolutionHero), locationOfCharacter, (Location) null);
      }
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.PlayerSentTroopsToQuest, Hero.MainHero);
    }

    private void MakeAlternativeSolutionTroopsReturn()
    {
      this.AlternativeSolutionHero.ChangeState(Hero.CharacterStates.Active);
      MobileParty.MainParty.MemberRoster.Add(this.AlternativeSolutionSentTroops);
      this.AlternativeSolutionSentTroops.Clear();
    }

    public void OnAlternativeSolutionSolvedAndTroopsAreReturning()
    {
      this._areIssueEffectsResolved = true;
      this.AddLog(new JournalLog(CampaignTime.Now, this.AlternativeSolutionEndLogDefault));
    }

    public void IssueFinalized()
    {
      this.IssueQuest = (QuestBase) null;
      CampaignEventDispatcher.Instance.RemoveListeners((object) this);
      Campaign.Current.IssueManager.DeactivateIssue(this);
      this._areIssueEffectsResolved = true;
      this.RemoveAllTrackedObjects();
      this.OnIssueFinalized();
    }

    public void CompleteIssueWithQuest()
    {
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueFinishedWithSuccess, this.IsTriedToSolveBefore ? Hero.MainHero : (Hero) null);
      this.IssueFinalized();
    }

    public void CompleteIssueWithTimedOut()
    {
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueTimedOut, this.IsTriedToSolveBefore ? Hero.MainHero : (Hero) null);
      this.IssueFinalized();
    }

    public void CompleteIssueWithStayAliveConditionsFailed()
    {
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueCancel, this.IsTriedToSolveBefore ? Hero.MainHero : (Hero) null);
      this.IssueFinalized();
    }

    public void CompleteIssueWithBetrayal()
    {
      if (this.IssueQuest != null && this.IssueQuest.IsOngoing)
        this.IssueQuest.CompleteQuestWithBetrayal();
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueFinishedWithBetrayal, this.IsTriedToSolveBefore ? Hero.MainHero : (Hero) null);
      this.IssueFinalized();
    }

    public void CompleteIssueWithFail(TextObject log = null)
    {
      if (this.IssueQuest != null && this.IssueQuest.IsOngoing)
        this.IssueQuest.CompleteQuestWithFail(log);
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueFail, this.IsTriedToSolveBefore ? Hero.MainHero : (Hero) null);
      this.IssueFinalized();
    }

    public void CompleteIssueWithCancel(TextObject log = null)
    {
      if (this.IssueQuest != null)
      {
        if (this.IssueQuest.IsOngoing)
          this.IssueQuest.CompleteQuestWithCancel(log);
      }
      else if (this.IsSolvingWithAlternative)
      {
        this.AddLog(new JournalLog(CampaignTime.Now, new TextObject("{=V5Za6d4h}Your troops have returned from their mission.")));
        this.MakeAlternativeSolutionTroopsReturn();
      }
      else if (this.IsSolvingWithLordSolution && log != null)
        this.AddLog(new JournalLog(CampaignTime.Now, log));
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueCancel, this.IsTriedToSolveBefore ? Hero.MainHero : (Hero) null);
      this.IssueFinalized();
    }

    public void CompleteIssueWithAiLord(Hero issueSolver)
    {
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueFinishedByAILord, issueSolver);
      this.IssueFinalized();
    }

    private void AlternativeSolutionEndWithSuccess()
    {
      if (this.AlternativeSolutionHero == null)
      {
        Debug.Print("AlternativeSolutionHero is null for " + this.StringId);
        Debug.Print("AlternativeSolutionSentTroops:");
        foreach (TroopRosterElement troopRosterElement in (List<TroopRosterElement>) this.AlternativeSolutionSentTroops.GetTroopRoster())
          Debug.Print("troop id: " + troopRosterElement.Character.StringId + " count:" + (object) troopRosterElement.Number);
      }
      int totalManCount = this.AlternativeSolutionSentTroops.TotalManCount;
      this.AlternativeSolutionSentTroops.KillNumberOfNonHeroTroopsRandomly(this._alternativeSolutionCasualtyCount);
      float num1 = 0.5f;
      float num2 = (float) (1.2000000476837158 - (double) this.AlternativeSolutionBaseNeededMenCount / (double) this.AlternativeSolutionSentTroops.TotalManCount);
      foreach (FlattenedTroopRosterElement troopRosterElement in this.AlternativeSolutionSentTroops.ToFlattenedRoster())
      {
        if (this.AlternativeSolutionBaseNeededMenCount < this.AlternativeSolutionSentTroops.TotalManCount)
          num1 /= (float) ((double) num2 * 0.89999997615814209 + (double) MBRandom.RandomFloat * 0.10000000149011612);
        if ((double) MBRandom.RandomFloat < (double) num1)
          this.AlternativeSolutionSentTroops.WoundTroop(troopRosterElement.Troop);
        if (troopRosterElement.Troop == this.AlternativeSolutionHero.CharacterObject && this.AlternativeSolutionHero.IsAlive)
          this.AlternativeSolutionHero.AddSkillXp(this._companionRewardSkill, (float) this.CompanionSkillRewardXP);
        num1 = 0.5f;
      }
      List<TroopRosterElement> all = this.AlternativeSolutionSentTroops.GetTroopRoster().FindAll((Predicate<TroopRosterElement>) (x => x.Character.UpgradeTargets.Length != 0 || x.Character.IsHero));
      int num3 = MBRandom.RandomInt(1, all.Count + 1);
      int num4 = (int) ((double) this._totalTroopXpAmount / (double) num3);
      for (int index = 0; index < num3 && all.Count > 0; ++index)
      {
        List<(TroopRosterElement, float)> weightList = new List<(TroopRosterElement, float)>();
        foreach (TroopRosterElement troopRosterElement in all)
          weightList.Add((troopRosterElement, (float) troopRosterElement.Number));
        int indexOfTroop = this.AlternativeSolutionSentTroops.FindIndexOfTroop(MBRandom.ChooseWeighted<TroopRosterElement>((IReadOnlyList<(TroopRosterElement, float)>) weightList).Character);
        this.AlternativeSolutionSentTroops.SetElementXp(indexOfTroop, num4 + this.AlternativeSolutionSentTroops.GetElementXp(indexOfTroop));
      }
      if (this.RewardGold > 0)
        GiveGoldAction.ApplyBetweenCharacters((Hero) null, Hero.MainHero, this.RewardGold);
      if (!TextObject.IsNullOrEmpty(this.IssueAlternativeSolutionSuccessLog))
        this.AddLog(new JournalLog(CampaignTime.Now, this.IssueAlternativeSolutionSuccessLog));
      TextObject empty = TextObject.Empty;
      TextObject textObject;
      if (this._alternativeSolutionCasualtyCount > 0)
      {
        int variable = totalManCount - this._alternativeSolutionCasualtyCount;
        textObject = new TextObject("{=fCHVyxJ1}{COMPANION.LINK} reported that {?COMPANION.GENDER}she{?}he{\\?} had resolved the matter. Out of {NUMBER1} {?(NUMBER1 > 1)}troops{?}troop{\\?} you sent {NUMBER2} {?(NUMBER2 > 1)}troops{?}troop{\\?} came back safe and sound.");
        textObject.SetTextVariable("NUMBER1", totalManCount);
        textObject.SetTextVariable("NUMBER2", variable);
      }
      else
      {
        textObject = new TextObject("{=WOwaHClt}{COMPANION.LINK} reported that {?COMPANION.GENDER}she{?}he{\\?} had resolved the matter. {NUMBER} {?(NUMBER > 1)}troops{?}troop{\\?} you sent joined back to your party.");
        textObject.SetTextVariable("NUMBER", totalManCount);
      }
      StringHelpers.SetCharacterProperties("COMPANION", this.AlternativeSolutionHero.CharacterObject, textObject);
      this.AddLog(new JournalLog(CampaignTime.Now, textObject));
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.SentTroopsFinishedQuest, Hero.MainHero);
    }

    public void StartIssueWithLordSolution()
    {
      this._issueDifficultyMultiplier = Campaign.Current.Models.IssueModel.GetIssueDifficultyMultiplier();
      if (this.LordSolutionStartLog != null && this.LordSolutionStartLog != TextObject.Empty)
        this.AddLog(new JournalLog(CampaignTime.Now, this.LordSolutionStartLog));
      this._issueState = IssueBase.IssueState.SolvingWithLordSolution;
      this.IsTriedToSolveBefore = true;
      CampaignEvents.BeforeGameMenuOpenedEvent.AddNonSerializedListener((object) this, new Action<MenuCallbackArgs>(this.BeforeGameMenuOpened));
    }

    private void BeforeGameMenuOpened(MenuCallbackArgs args)
    {
      if (this._issueState != IssueBase.IssueState.SolvingWithLordSolution || Campaign.Current.GameMenuManager.NextLocation != null || !(GameStateManager.Current.ActiveState is MapState))
        return;
      if (this.CounterOfferHero != null)
      {
        if (this.IssueOwner.CurrentSettlement == null)
          return;
        CampaignMapConversation.OpenConversation(new ConversationCharacterData(CharacterObject.PlayerCharacter), new ConversationCharacterData(this.CounterOfferHero.CharacterObject));
      }
      else
        this.CompleteIssueWithLordSolutionWithRefuseCounterOffer();
    }

    public void CompleteIssueWithAlternativeSolution()
    {
      if ((double) MBRandom.RandomFloat > (double) this._failureChance)
      {
        this.AlternativeSolutionEndWithSuccessConsequence();
        this.AlternativeSolutionEndWithSuccess();
      }
      else
      {
        this.AlternativeSolutionEndWithFailureConsequence();
        this.AlternativeSolutionEndWithFail();
      }
      this.MakeAlternativeSolutionTroopsReturn();
      this.IssueFinalized();
    }

    private void AlternativeSolutionEndWithFail()
    {
      TextObject empty = TextObject.Empty;
      int totalManCount = this.AlternativeSolutionSentTroops.TotalManCount;
      if (this.AlternativeSolutionHasCasualties)
      {
        this.AlternativeSolutionSentTroops.KillNumberOfNonHeroTroopsRandomly(this._alternativeSolutionCasualtyCount);
        this.AlternativeSolutionHero.MakeWounded();
      }
      TextObject logText;
      if (this.AlternativeSolutionHasCasualties && this._alternativeSolutionCasualtyCount > 0)
      {
        logText = new TextObject("{=yxwuGcDo}{COMPANION.LINK} has failed to resolve the matter. Out of {NUMBER1} troops you sent {NUMBER2} troops came back safe and sound.");
        logText.SetTextVariable("NUMBER1", totalManCount);
        logText.SetTextVariable("NUMBER2", totalManCount - this._alternativeSolutionCasualtyCount);
      }
      else
      {
        logText = new TextObject("{=k6fpAw92}{COMPANION.LINK} has failed to resolve the matter. {NUMBER} troops came back safe and sound.");
        logText.SetTextVariable("NUMBER", totalManCount);
      }
      if (!TextObject.IsNullOrEmpty(this.IssueAlternativeSolutionFailLog))
        this.AddLog(new JournalLog(CampaignTime.Now, this.IssueAlternativeSolutionFailLog));
      StringHelpers.SetCharacterProperties("COMPANION", this.AlternativeSolutionHero.CharacterObject);
      this.AddLog(new JournalLog(CampaignTime.Now, logText));
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.SentTroopsFailedQuest, Hero.MainHero);
    }

    public void CompleteIssueWithLordSolutionWithRefuseCounterOffer()
    {
      if (this.LordSolutionCounterOfferRefuseLog != null && this.LordSolutionCounterOfferRefuseLog != TextObject.Empty)
        this.AddLog(new JournalLog(CampaignTime.Now, this.LordSolutionCounterOfferRefuseLog));
      ChangeClanInfluenceAction.Apply(Clan.PlayerClan, (float) -this.NeededInfluenceForLordSolution);
      if (this.RewardGold > 0)
        GiveGoldAction.ApplyBetweenCharacters((Hero) null, Hero.MainHero, this.RewardGold);
      this.LordSolutionConsequenceWithRefuseCounterOffer();
      this.IssueFinalized();
      CampaignEventDispatcher.Instance.OnIssueUpdated(this, IssueBase.IssueUpdateDetails.IssueFinishedWithSuccess, Hero.MainHero);
    }

    public void CompleteIssueWithLordSolutionWithAcceptCounterOffer()
    {
      if (this.LordSolutionCounterOfferAcceptLog != null && this.LordSolutionCounterOfferAcceptLog != TextObject.Empty)
        this.AddLog(new JournalLog(CampaignTime.Now, this.LordSolutionCounterOfferAcceptLog));
      this.LordSolutionConsequenceWithAcceptCounterOffer();
      this.CompleteIssueWithBetrayal();
    }

    internal bool CheckPreconditions(Hero issueGiver, out TextObject explanation)
    {
      explanation = new TextObject("{=!}{EXPLANATION}");
      if (!this.IssueStayAliveConditions() && this.IsOngoingWithoutQuest)
      {
        this.CompleteIssueWithCancel();
        return false;
      }
      IssueBase.PreconditionFlags flag1;
      Hero relationHero;
      SkillObject skill;
      bool flag2 = this.CanPlayerTakeQuestConditions(issueGiver, out flag1, out relationHero, out skill);
      bool flag3 = false;
      if (!this.IssueQuestCanBeDuplicated)
      {
        foreach (KeyValuePair<Hero, IssueBase> issue in Campaign.Current.IssueManager.Issues)
        {
          IssueBase issueBase = issue.Value;
          if ((issueBase.IsSolvingWithQuest || issueBase.IsSolvingWithAlternative) && issueBase.GetType() == this.GetType())
          {
            flag3 = true;
            flag2 = false;
          }
        }
      }
      if ((flag1 & IssueBase.PreconditionFlags.AtWar) == IssueBase.PreconditionFlags.AtWar)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=21dlZJt6}I don't wish to speak about that. As you know, our factions are at war."));
      else if (flag3)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=HvY7wjHt}I don't think you can help me. I think you may have other, similar commitments that could interfere."));
      else if ((flag1 & IssueBase.PreconditionFlags.NotInSameFaction) == IssueBase.PreconditionFlags.NotInSameFaction)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=rBPI2dvX}I don't need the service of strangers. I work only with lords of the realm and loyal mercenaries.[ib:closed][if:convo_grave]"));
      else if ((flag1 & IssueBase.PreconditionFlags.MainHeroIsKingdomLeader) == IssueBase.PreconditionFlags.MainHeroIsKingdomLeader || (flag1 & IssueBase.PreconditionFlags.PlayerIsOwnerOfSettlement) == IssueBase.PreconditionFlags.PlayerIsOwnerOfSettlement)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=dYJKy2mO}Thank you for asking my {?PLAYER.GENDER}lady{?}lord{\\?}, but I can't bother you with such an unimportant issue."));
      else if ((flag1 & IssueBase.PreconditionFlags.ClanTier) == IssueBase.PreconditionFlags.ClanTier)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=QOiPDGbf}I have never heard of your clan. I am not sure if I can rely on you or not.[ib:closed][if:convo_grave]"));
      else if ((flag1 & IssueBase.PreconditionFlags.Renown) == IssueBase.PreconditionFlags.Renown)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=7uJcPQnc}I don't think you can help me. I'm looking for someone with a bit more, shall we say, renown..."));
      else if ((flag1 & IssueBase.PreconditionFlags.Relation) == IssueBase.PreconditionFlags.Relation)
      {
        TextObject textObject;
        if (issueGiver == relationHero)
        {
          textObject = new TextObject("{=Cn4lnECZ}You and I do not have a good history... I don't trust you.[ib:closed][if:convo_grave]");
        }
        else
        {
          textObject = new TextObject("{=5ZJMa7Om}I don't think you can help me. I've heard you have a history with {HERO.LINK}, and, well, that could complicate things...[ib:closed][if:convo_grave]");
          StringHelpers.SetCharacterProperties("HERO", relationHero.CharacterObject, textObject);
        }
        explanation.SetTextVariable("EXPLANATION", textObject);
      }
      else if ((flag1 & IssueBase.PreconditionFlags.Skill) == IssueBase.PreconditionFlags.Skill)
      {
        TextObject variable = new TextObject("{=S9yUBtKc}I don't think you can help me. You need to have some experience in {SKILL_NAME}...");
        variable.SetTextVariable("SKILL_NAME", skill.Name);
        explanation.SetTextVariable("EXPLANATION", variable);
      }
      else if ((flag1 & IssueBase.PreconditionFlags.Money) == IssueBase.PreconditionFlags.Money)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=GhcUKfbJ}I don't think you can help me. I need someone who has some gold to spend...[ib:closed]"));
      else if ((flag1 & IssueBase.PreconditionFlags.Influence) == IssueBase.PreconditionFlags.Influence)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=b6Zc1yre}I don't think you can help me. You'd need a bit of influence..."));
      else if ((flag1 & IssueBase.PreconditionFlags.Wounded) == IssueBase.PreconditionFlags.Wounded)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=BUf9WeyN}I don't think you can help me. You should rest for a while and let your wounds heal."));
      else if ((flag1 & IssueBase.PreconditionFlags.NotEnoughTroops) == IssueBase.PreconditionFlags.NotEnoughTroops)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=dCv4Qbr6}I don't think you can help me. You don't have enough troops for this task."));
      else if ((flag1 & IssueBase.PreconditionFlags.PartySizeLimit) == IssueBase.PreconditionFlags.PartySizeLimit)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=yaiQgyfB}I was planning to give you some troops to solve this task but it seems like you would have difficulties taking any more into your company."));
      else if ((flag1 & IssueBase.PreconditionFlags.ClanIsMercenary) == IssueBase.PreconditionFlags.ClanIsMercenary)
        explanation.SetTextVariable("EXPLANATION", new TextObject("{=vz4M8SRn}I do have one particular task, but it is not really suited to a mercenary.Please carry on with your other duties."));
      else
        explanation.SetTextVariable("EXPLANATION", TextObject.Empty);
      return flag2;
    }

    internal void AfterCreation() => this.AfterIssueCreation();

    public void InitializeIssueOnSettlementOwnerChange()
    {
      if (!this.IsThereLordSolution)
        return;
      Campaign.Current.ConversationManager.RemoveRelatedLines((object) this);
    }

    private void OnSettlementOwnerChanged(
      Settlement settlement,
      bool openToClaim,
      Hero newOwner,
      Hero oldOwner,
      Hero capturerHero,
      ChangeOwnerOfSettlementAction.ChangeOwnerOfSettlementDetail detail)
    {
      if (this.IssueSettlement != settlement && (this.IssueSettlement != null || this.IssueOwner.CurrentSettlement != settlement || !this.IssueOwner.IsNoncombatant))
        return;
      Campaign.Current.ConversationManager.RemoveRelatedLines((object) this);
    }

    public void AddLog(JournalLog log)
    {
      this._journalEntries.Add(log);
      CampaignEventDispatcher.Instance.OnIssueLogAdded(this, false);
    }

    private void RemoveAllTrackedObjects()
    {
      foreach (ITrackableBase trackedObject in this._trackedObjects)
        Campaign.Current.VisualTrackerManager.RemoveTrackedObject(trackedObject);
      this._trackedObjects.Clear();
    }

    public void AddTrackedObject(ITrackableCampaignObject o)
    {
      this._trackedObjects.Add(o);
      Campaign.Current.VisualTrackerManager.RegisterObject(o);
    }

    public void ToggleTrackedObjects(bool enableTrack)
    {
      if (enableTrack)
      {
        foreach (ITrackableCampaignObject trackedObject in this._trackedObjects)
          Campaign.Current.VisualTrackerManager.RegisterObject(trackedObject);
      }
      else
      {
        foreach (ITrackableBase trackedObject in this._trackedObjects)
          Campaign.Current.VisualTrackerManager.RemoveTrackedObject(trackedObject);
      }
    }

    internal enum IssueState
    {
      Ongoing,
      SolvingWithQuestSolution,
      SolvingWithAlternativeSolution,
      SolvingWithLordSolution,
    }

    [Flags]
    public enum AlternativeSolutionScaleFlag : uint
    {
      None = 0,
      Duration = 1,
      RequiredTroops = 2,
      Casualties = 4,
      FailureRisk = 8,
    }

    [Flags]
    protected enum PreconditionFlags : uint
    {
      None = 0,
      Relation = 1,
      Skill = 2,
      Money = 4,
      Renown = 8,
      Influence = 16, // 0x00000010
      Wounded = 32, // 0x00000020
      AtWar = 64, // 0x00000040
      ClanTier = 128, // 0x00000080
      NotEnoughTroops = 256, // 0x00000100
      NotInSameFaction = 512, // 0x00000200
      PartySizeLimit = 1024, // 0x00000400
      ClanIsMercenary = 2048, // 0x00000800
      MainHeroIsKingdomLeader = 16384, // 0x00004000
      PlayerIsOwnerOfSettlement = 32768, // 0x00008000
    }

    public enum IssueUpdateDetails
    {
      None,
      PlayerStartedIssueQuestClassicSolution,
      PlayerSentTroopsToQuest,
      SentTroopsFinishedQuest,
      SentTroopsFailedQuest,
      IssueFinishedWithSuccess,
      IssueFinishedWithBetrayal,
      IssueFinishedByAILord,
      IssueFail,
      IssueCancel,
      IssueTimedOut,
    }

    public enum IssueFrequency
    {
      VeryCommon,
      Common,
      Rare,
    }
  }
}
